package com.scorpio.order.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

import com.scorpio.appuser.domain.AppUserEntity;
import com.scorpio.appuser.domain.UserAddressEntity;
import com.scorpio.appuser.domain.UserInvoiceEntity;
import com.scorpio.appuser.domain.UserShopCartEntity;
import com.scorpio.appuser.service.UserAddressService;
import com.scorpio.appuser.service.UserInvoiceService;
import com.scorpio.appuser.service.UserShopCartService;
import com.scorpio.common.exception.CustomException;
import com.scorpio.common.utils.ConvertUtils;
import com.scorpio.common.utils.DateUtils;
import com.scorpio.common.utils.MathUtil;
import com.scorpio.goods.domain.GoodsEntity;
import com.scorpio.goods.domain.GoodsSpecEntity;
import com.scorpio.goods.enums.GoodsStatusEnum;
import com.scorpio.goods.service.GoodsService;
import com.scorpio.goods.service.GoodsSpecService;
import com.scorpio.manager.AsyncManager;
import com.scorpio.mqtt.service.MqttService;
import com.scorpio.order.domain.OrderGoodsEntity;
import com.scorpio.order.domain.OrderSnsEntity;
import com.scorpio.order.dto.OrderDTO;
import com.scorpio.order.dto.OrderDetailsDTO;
import com.scorpio.order.dto.OrderItemDTO;
import com.scorpio.order.enums.OrderStatusEmun;
import com.scorpio.order.service.OrderGoodsService;
import com.scorpio.order.service.OrderSnsServer;
import com.scorpio.order.vo.OrderQueryVo;
import com.scorpio.order.vo.PayOrderVo;
import com.scorpio.order.vo.SubmitShopCartOrderVo;
import com.scorpio.order.vo.SubmitShopOrderVo;
import com.scorpio.pay.enums.PayTypeEnum;
import com.scorpio.redis.cachelock.RedisLock;
import com.scorpio.redis.cachelock.RedisLockException;
import com.scorpio.sdk.dto.WXMiniPayPackge;
import com.scorpio.sdk.service.WXPayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.scorpio.order.mapper.OrderMapper;
import com.scorpio.order.domain.OrderEntity;
import com.scorpio.order.service.OrderService;
import com.scorpio.common.service.impl.BaseServiceImpl;
import org.springframework.transaction.annotation.Transactional;

/**
 * 订单Service业务层处理
 *
 * @author scorpio
 * @date 2021-11-29
 */
@Service
public class OrderServiceImpl extends BaseServiceImpl<OrderMapper, OrderEntity> implements OrderService {


    @Autowired
    private RedisLock redisLock;

    @Autowired
    private UserShopCartService userShopCartService;

    @Autowired
    private GoodsSpecService specService;

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private UserAddressService userAddressService;

    @Autowired
    private OrderGoodsService orderGoodsService;

    @Autowired
    private UserInvoiceService userInvoiceService;

    @Autowired
    private WXPayService wxPayService;

    @Autowired
    private MqttService mqttService;

    @Autowired
    private OrderSnsServer orderSnsServer;

    @Override
    public int countByStatus(Long uid, OrderStatusEmun statusEnum) {
        return baseDao.countByStatus(uid, statusEnum.getValue());
    }

    @Override
    public List<OrderDTO> orderList(OrderQueryVo vo) {
        vo.setPage();
        List<OrderEntity> list = baseDao.appList(vo.uid, vo.getStatus(), vo.getOffset(), vo.getLimit());
        List<OrderDTO> dtos = ConvertUtils.sourceToTarget(list, OrderDTO.class);
        for (OrderDTO dto : dtos) {
            dto.setOrderItems(ConvertUtils.sourceToTarget(orderGoodsService.selectByOrder(dto.getId()), OrderItemDTO.class));
        }
        return dtos;
    }

    @Override
    public OrderDetailsDTO orderDetails(AppUserEntity user, Long id) {
        OrderEntity entity = baseDao.selectById(id);
        if (entity != null && !entity.getUid().equals(user.getId())) {
            throw new CustomException("无权限");
        } else if (entity == null) {
            throw new CustomException("订单不存在");
        }
        OrderDetailsDTO dto = ConvertUtils.sourceToTarget(entity, OrderDetailsDTO.class);
        dto.setOrderItems(ConvertUtils.sourceToTarget(orderGoodsService.selectByOrder(dto.getId()), OrderItemDTO.class));
        if (OrderStatusEmun.Status0.getValue().equals(dto.getStatus())) {
            long endTime = dto.getCreateTime().getTime() + DateUtils.MILLIS_PER_DAY;
            if (endTime - System.currentTimeMillis() > 0) {
                dto.setTimeExplain(String.format("请在%s内完成付款", DateUtils.getDatePoor(new Date(endTime), new Date(System.currentTimeMillis()))));
            }
        }
        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderEntity submitShopCart(SubmitShopCartOrderVo vo) {
        String lockKey = "OrderServiceImpl_submit:" + vo.uid;
        List<String> lockKeys = new ArrayList<>();
        if (redisLock.lock(lockKey, 30)) {
            try {
                OrderEntity orderEntity = new OrderEntity();
                List<OrderGoodsEntity> goodsList = new ArrayList<>();
                UserAddressEntity addressEntity = userAddressService.selectByUser(vo.uid, vo.getAddressId());
                if (addressEntity == null) {
                    throw new CustomException("请重新选择配送地址");
                }
                if (vo.getInvoiceId() != null) {
                    UserInvoiceEntity entity = userInvoiceService.selectById(vo.getInvoiceId());
                    if (entity == null || !entity.getUid().equals(vo.uid)) {
                        throw new CustomException("无效的开票信息");
                    }
                    orderEntity.setInvoiceName(entity.getName());
                    orderEntity.setCreditCode(entity.getCreditCode());
                    orderEntity.setMailbox(entity.getMailbox());
                }
                float moneyTotal = 0;
                int goodsTotal = 0;
                for (Long id : vo.getIds()) {
                    UserShopCartEntity entity = userShopCartService.selectByUser(vo.uid, id);
                    if (entity == null) {
                        throw new CustomException("部分商品不存在");
                    }
                    String key = "spec_number:" + entity.getSpecNumber();
                    lockKeys.add(key);
                    if (!redisLock.lock(key, 30)) {
                        throw new RedisLockException();
                    }
                    GoodsSpecEntity specEntity = specService.selectByNumber(entity.getSpecNumber());
                    GoodsEntity goodsEntity = goodsService.selectById(specEntity.getGoodsId());
                    if (specEntity == null || goodsEntity == null || !GoodsStatusEnum.Status0.getValue().equals(specEntity.getStatus())
                            || !GoodsStatusEnum.Status0.getValue().equals(goodsEntity.getStatus())) {
                        throw new CustomException("部分商品不存在或已下架");
                    }
                    specService.updateInventory(specEntity.getId(), entity.getAmountTotal());
                    OrderGoodsEntity orderGoods = new OrderGoodsEntity();
                    orderGoods.setGoodsId(goodsEntity.getId());
                    orderGoods.setGoodsName(goodsEntity.getGoodsName());
                    orderGoods.setSpecId(specEntity.getId());
                    orderGoods.setSpecName(specService.getSpecName(specEntity));
                    orderGoods.setSpecNumber(specEntity.getNumber());
                    orderGoods.setBuyTotal(entity.getAmountTotal());
                    orderGoods.setPayMoney(specEntity.getPresentPrice());
                    orderGoods.setImageUrl(specEntity.getImage());
                    goodsList.add(orderGoods);
                    goodsTotal += entity.getAmountTotal();
                    moneyTotal += entity.getAmountTotal() * orderGoods.getPayMoney();
                }
                if (goodsList.size() == 0) {
                    throw new CustomException("请选择购买的商品");
                }
                if (moneyTotal <= 0) {
                    throw new CustomException("无效提交订单");
                }
                //创建18位订单号
                String orderSn = MathUtil.getRandLetter(MathUtil.NUMERIC, DateUtils.dateTimeNow(), 4);
                orderEntity.setMoney(moneyTotal);
                orderEntity.setPracticalMoney(orderEntity.getMoney());
                orderEntity.setGoodsTotal(goodsTotal);
                orderEntity.setPayType(PayTypeEnum.WeChatPay.getValue());
                orderEntity.setUid(vo.uid);
                orderEntity.setStatus(OrderStatusEmun.Status0.getValue());
                orderEntity.setOrderSn(orderSn);
                orderEntity.setMobile(addressEntity.getMobile());
                orderEntity.setProvince(addressEntity.getProvinceName());
                orderEntity.setCity(addressEntity.getCityName());
                orderEntity.setAddress((addressEntity.getDistrictName() != null ? addressEntity.getDistrictName() : "") + addressEntity.getAddress());
                orderEntity.setTruename(addressEntity.getTruename());
                orderEntity.setRemark(vo.getRemark());
                if (baseDao.insert(orderEntity) == 0 || orderSnsServer.save(orderEntity) == 0) {
                    throw new CustomException("下单失败");
                }
                for (OrderGoodsEntity goodsEntity : goodsList) {
                    goodsEntity.setOrderId(orderEntity.getId());
                    if (orderGoodsService.save(goodsEntity) == 0) {
                        throw new CustomException("下单失败");
                    }
                }
                userShopCartService.deleteShopCart(vo.uid, vo.getIds());
                AsyncManager.me().execute(new TimerTask() {
                    @Override
                    public void run() {
                        mqttService.pushOrderOverdueQueu(orderEntity.getOrderSn(), System.currentTimeMillis() + DateUtils.MILLIS_PER_DAY + 2000);
                    }
                }, 100, TimeUnit.MILLISECONDS);
                return orderEntity;
            } finally {
                redisLock.unlock(lockKey);
                for (String key : lockKeys) {
                    redisLock.unlock(key);
                }
            }
        }
        throw new RedisLockException();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderEntity submitShopOrder(SubmitShopOrderVo vo) {
        String lockKey = "OrderServiceImpl_submit:" + vo.uid;
        String lockSpecKey = null;
        if (redisLock.lock(lockKey, 5)) {
            try {
                OrderEntity orderEntity = new OrderEntity();
                UserAddressEntity addressEntity = userAddressService.selectByUser(vo.uid, vo.getAddressId());
                if (addressEntity == null) {
                    throw new CustomException("请重新选择配送地址");
                }
                lockSpecKey = "spec_number:" + vo.getSpecNumber();
                if (!redisLock.lock(lockSpecKey, 30)) {
                    throw new RedisLockException();
                }
                GoodsSpecEntity specEntity = specService.selectByNumber(vo.getSpecNumber());
                GoodsEntity goodsEntity = goodsService.selectById(specEntity.getGoodsId());
                if (specEntity == null || goodsEntity == null || !GoodsStatusEnum.Status0.getValue().equals(specEntity.getStatus())
                        || !GoodsStatusEnum.Status0.getValue().equals(goodsEntity.getStatus())) {
                    throw new CustomException("商品不存在或已下架");
                }
                if (vo.getInvoiceId() != null) {
                    UserInvoiceEntity entity = userInvoiceService.selectById(vo.getInvoiceId());
                    if (entity == null || !entity.getUid().equals(vo.uid)) {
                        throw new CustomException("无效的开票信息");
                    }
                    orderEntity.setInvoiceName(entity.getName());
                    orderEntity.setCreditCode(entity.getCreditCode());
                    orderEntity.setMailbox(entity.getMailbox());
                }
                specService.updateInventory(specEntity.getId(), vo.getBuyTotal());
                OrderGoodsEntity orderGoods = new OrderGoodsEntity();
                orderGoods.setGoodsId(goodsEntity.getId());
                orderGoods.setGoodsName(goodsEntity.getGoodsName());
                orderGoods.setSpecId(specEntity.getId());
                orderGoods.setSpecName(specService.getSpecName(specEntity));
                orderGoods.setSpecNumber(specEntity.getNumber());
                orderGoods.setBuyTotal(vo.getBuyTotal());
                orderGoods.setPayMoney(specEntity.getPresentPrice());
                orderGoods.setImageUrl(specEntity.getImage());
                if (orderGoods.getPayMoney() <= 0) {
                    throw new CustomException("无效提交订单");
                }
                //创建18位订单号
                String orderSn = MathUtil.getRandLetter(MathUtil.NUMERIC, DateUtils.dateTimeNow(), 4);
                orderEntity.setMoney(vo.getBuyTotal() * orderGoods.getPayMoney());
                orderEntity.setPracticalMoney(orderEntity.getMoney());
                orderEntity.setGoodsTotal(orderGoods.getBuyTotal());
                orderEntity.setPayType(PayTypeEnum.WeChatPay.getValue());
                orderEntity.setUid(vo.uid);
                orderEntity.setStatus(OrderStatusEmun.Status0.getValue());
                orderEntity.setOrderSn(orderSn);
                orderEntity.setMobile(addressEntity.getMobile());
                orderEntity.setProvince(addressEntity.getProvinceName());
                orderEntity.setCity(addressEntity.getCityName());
                orderEntity.setAddress((addressEntity.getDistrictName() != null ? addressEntity.getDistrictName() : "") + addressEntity.getAddress());
                orderEntity.setTruename(addressEntity.getTruename());
                orderEntity.setRemark(vo.getRemark());
                if (baseDao.insert(orderEntity) == 0 || orderSnsServer.save(orderEntity) == 0) {
                    throw new CustomException("下单失败");
                }
                orderGoods.setOrderId(orderEntity.getId());
                if (orderGoodsService.save(orderGoods) == 0) {
                    throw new CustomException("下单失败");
                }
                AsyncManager.me().execute(new TimerTask() {
                    @Override
                    public void run() {
                        mqttService.pushOrderOverdueQueu(orderEntity.getOrderSn(), System.currentTimeMillis() + DateUtils.MILLIS_PER_DAY + 2000);
                    }
                }, 100, TimeUnit.MILLISECONDS);
                return orderEntity;
            } finally {
                redisLock.unlock(lockKey);
                if (lockSpecKey != null) {
                    redisLock.unlock(lockSpecKey);
                }
            }
        }
        throw new RedisLockException();
    }

    @Override
    public WXMiniPayPackge placeOrder(AppUserEntity user, PayOrderVo vo) {
        OrderEntity entity = baseDao.selectOrderSn(vo.getOrderSn());
        if (entity == null) {
            OrderSnsEntity snsEntity = orderSnsServer.selectByOrderSn(vo.getOrderSn());
            if (snsEntity == null) {
                throw new CustomException("订单号已失效，请刷新订单");
            }
            entity = baseDao.selectById(snsEntity.getOid());
        }
        if (!user.getId().equals(entity.getUid())) {
            throw new CustomException("非法操作");
        } else if (!OrderStatusEmun.Status0.getValue().equals(entity.getStatus())) {
            throw new CustomException("请刷新订单状态");
        }
        return wxPayService.payJSAPICode(entity.getOrderSn(), user.getWxOpenId(), "商品", (int) (entity.getPracticalMoney() * 100));
    }

}
